﻿namespace Lite.Common
{
    using System;
    using System.Threading;

    /// <summary>
    /// Contains extension methods for asynchronously invoking events and
    /// delegates.
    /// </summary>
    public static class ThreadUtility
    {
        /// <summary>
        /// Asynchronously execute the specified event.
        /// </summary>
        /// <typeparam name="TEventArgs">
        /// The type of data to pass to the event handlers.
        /// </typeparam>
        /// <param name="eventMulticastDelegate">
        /// A collection of event handlers in the form of a multicast delegate.
        /// </param>
        /// <param name="sender">
        /// The object that raised the event.
        /// </param>
        /// <param name="args">
        /// The data to pass to the event handlers.
        /// </param>
        /// <remarks>
        /// Note that each event handler will be invoked on a seperate thread
        /// and so may not execute sequentially.
        /// </remarks>
        public static void InvokeAsync<TEventArgs>(this EventHandler<TEventArgs> eventMulticastDelegate, object sender, TEventArgs args)
            where TEventArgs : EventArgs
        {
            if (eventMulticastDelegate == null)
            {
                throw new ArgumentNullException("eventMulticastDelegate");
            }

            foreach (EventHandler<TEventArgs> eventDelegate in eventMulticastDelegate.GetInvocationList())
            {
                ThreadPool.QueueUserWorkItem(state => eventDelegate(sender, args));
            }
        }

        /// <summary>
        /// Asynchronously execute the specified delegate.
        /// </summary>
        /// <param name="eventMulticastDelegate">
        /// A collection of event handlers in the form of a multicast delegate.
        /// </param>
        /// <param name="sender">
        /// The object that raised the event.
        /// </param>
        /// <param name="args">
        /// The data to pass to the event handlers.
        /// </param>
        /// <remarks>
        /// Note that each event handler will be invoked on a seperate thread
        /// and so may not execute sequentially.
        /// </remarks>
        public static void InvokeAsync(this Delegate eventMulticastDelegate, object sender, EventArgs args)
        {
            if (eventMulticastDelegate == null)
            {
                throw new ArgumentNullException("eventMulticastDelegate");
            }

            foreach (Delegate eventDelegate in eventMulticastDelegate.GetInvocationList())
            {
                ThreadPool.QueueUserWorkItem(state => eventDelegate.DynamicInvoke(sender, args));
            }
        }
    }
}
